package drp.snowbell.part;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.json.JSONObject;

import weibo.toyger.common.util.LockableArrayList;
import weibo.toyger.common.util.LockableMap;
import weibo.toyger.common.util.StrHelper;
import weibo.toyger.core.exception.CannotAccessException;
import weibo.toyger.core.exception.CannotFindSkillException;
import weibo.toyger.core.farm.Property;


/**
 * 技能管理器.
 * 
 * @author jimmy
 * 
 */
public class PartManager {

	private static Map<String, PartBlueprint> allSkillMap = new HashMap<String, PartBlueprint>();
	private static Map<String, LockableMap<String, PartBlueprint>> skillMapMap = new HashMap<String, LockableMap<String, PartBlueprint>>();

	private static boolean isLock = false;

	private static Collection<PartBlueprint> emptyList;

	/**
	 * 注册关系.
	 * 
	 * @param func
	 *            关系
	 */
	public static void register(PartBlueprint skillDna) {
		if (isLock) {
			throw new CannotAccessException();
		}

		if (skillDna == null || StrHelper.isNullOrEmpty(skillDna.getName())) {
			throw new IllegalArgumentException("skillDna");
		} else {
			allSkillMap.put(skillDna.getName(), skillDna);
		}
	}

	/**
	 * 一个模块使用指定一组技能,如果此技能不存在则抛错,或者该模块已经使用此技能也抛错.注意每个模块只能调用一次此函数.
	 * 
	 * @param beanName
	 *            模块名称.
	 * @param skillNameList
	 *            技能名称的数组.
	 * @param param
	 *            初始化技能的参数.一般为json数据.如果为空则设置为默认参数
	 */
	public static void useSkill(String beanName, String skillName, String param) {

		if (isLock) {
			throw new CannotAccessException();
		}
		PartBlueprint skillDna = allSkillMap.get(skillName);
		if (skillDna == null) {
			// 说明还没注册此技能
			throw new CannotFindSkillException(skillName);
		}

		LockableMap<String, PartBlueprint> list = null;
		if (skillMapMap.containsKey(beanName)) {
			list = skillMapMap.get(beanName);
		} else {
			list = new LockableMap<String, PartBlueprint>();
			skillMapMap.put(beanName, list);
		}

		// 复制skillDna,使每个模块有自己的一个SkillDna的实例.
		Collection<Property> propList = skillDna.getPropertyList();
		Collection<Property> newPropList = new ArrayList<Property>();
		Class<? extends IPart> clazz = skillDna.getSkillClass();
		for (Property p : propList) {
			String relaExp = null;
			if (p.getRelationExp() != null) {
				relaExp = p.getRelationExp().getRelationExpString();
			}
			String fullTextConfig = (new JSONObject(p.getFullTextConfig())).toString();
			Property newProp = new Property(p.getName(), p.getSetterName(), p.getGetterName(), beanName, p.getSkillName(), p.getLabel(), p.getDbFieldName(), p.getDbType(),
					p.getDbLength(), p.getValueType(), p.isUnique(), p.isRequired(), p.isReadOnly(), relaExp, p.getDbDefaultValue(), p.isEditable(), fullTextConfig);
			newPropList.add(newProp);
		}
		String paramString = null;
		if (!StrHelper.isNullOrEmpty(param)) {
			paramString = param;
		} else {
			// 如果参数为空则获取默认参数
			paramString = skillDna.getDefaultParameter();
		}
		PartBlueprint newSkillDna = new PartBlueprint(clazz, skillDna.getName(), newPropList, paramString);
		list.put(skillName, newSkillDna);
	}

	/**
	 * 锁定.注册完毕,调用此函数后所有元素不能修改
	 */
	public static void lock() {
		isLock = true;
		Collection<LockableMap<String, PartBlueprint>> lists = skillMapMap.values();
		for (LockableMap<String, PartBlueprint> list : lists) {
			list.lock();
		}
	}

	/**
	 * 解锁.如果需要动态增加技能请先解锁.
	 */
	public static void unlock() {
		isLock = false;
		if (skillMapMap != null) {
			Collection<LockableMap<String, PartBlueprint>> lists = skillMapMap.values();
			for (LockableMap<String, PartBlueprint> list : lists) {
				list.unlock();
			}
		}
	}

	/**
	 * 获取关系 ,注意此函数null不安全
	 * 
	 * @param skillName
	 * @return 关系,如果没有返回null
	 */
	public static PartBlueprint getSkillDna(String beanName, String skillName) {
		PartBlueprint ret = null;
		if (skillMapMap.containsKey(beanName)) {
			Map<String, PartBlueprint> skilldnaMap = skillMapMap.get(beanName);
			ret = skilldnaMap.get(skillName);
		}

		return ret;
	}

	/**
	 * 获取指定模块的技能列表,此函数null安全
	 * 
	 * @param beanName
	 *            模块名称
	 * @return 关系列表,如果没有指定值返回size为0的列表
	 */
	public static Collection<PartBlueprint> getSkillDnaList(String beanName) {
		Collection<PartBlueprint> list = null;
		if (skillMapMap.containsKey(beanName)) {
			list = skillMapMap.get(beanName).values();
		} else {
			if (emptyList == null) {
				LockableArrayList<PartBlueprint> lockList = new LockableArrayList<PartBlueprint>();
				lockList.lock();
				emptyList = lockList;
			}
			list = emptyList;
		}
		return list;
	}

}
